/*
  LinPVR - Linux Personal Video Recorder
  Copyright (C) 2006 Kamil Pawlowski <kamilpe@gmail.com>

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 2
  of the License, or (at your option) any later version.
  
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
*/
#include <glib.h>
#include <time.h>
#include <string.h>
#include "debug.h"

debug_t debug;
GString *string = NULL;

event_t *new_event() 
{
  event_t *event;
  if (debug.queue <= EVENTS_IN_MEMORY) {
    event = &debug.events[debug.queue];
    debug.queue ++;
  } else {
    memmove(debug.events, &debug.events[1], sizeof(event_t) * (EVENTS_IN_MEMORY));
    event = &debug.events[EVENTS_IN_MEMORY];
  }
  return event;
}

void debug_init() {
  debug.queue = 0;
}
void debug_enter(const char *funcname, int line, const char *file) {
  event_t *event = new_event();
  event->type = TYPE_FUNC_TRACE;
  event->code = 0;
  event->file = file;
  event->line = line;
  g_strlcpy(event->desc, funcname, 1000);
#ifdef VERBOSE
  g_printf("%s  (%s:%d)\n",event->desc, event->file, event->line);
#endif
}

int debug_error(int code, int line, const char *file) {
  event_t *event;

  if (code >= 0) 
    return code;

  event = new_event();
  event->type = TYPE_ERROR;
  event->code = code;
  event->file = file;
  event->line = line;
  switch(code) {
  case ERR_OPEN: 
    g_strlcpy(event->desc,"Can't open specified file", 1024); break;
  case ERR_NO_V4L2:
    g_strlcpy(event->desc,"This is problably not an v4l2 device", 1024); break;
  case ERR_NO_CAPTURE:
    g_strlcpy(event->desc,"This device can't capture", 1024); break;
  case ERR_FORMAT:
    g_strlcpy(event->desc,"Device don't want accept proposed pixel format", 1024); break;
  case ERR_BUFFERS_REQUEST:
    g_strlcpy(event->desc,"Can't request video frame buffers", 1024); break;
  case ERR_BUFFERS_FEW:
    g_strlcpy(event->desc,"Quantity of video frame buffers is too low", 1024); break;
  case ERR_MMAP:
    g_strlcpy(event->desc,"Problem to map buffer", 1024); break;
  case ERR_STREAMON:
    g_strlcpy(event->desc,"Device deny \"stream on\" command", 1024); break;
  case ERR_MALLOC:
    g_strlcpy(event->desc,"Memory error", 1024); break;
  case ERR_THEORA:
    g_strlcpy(event->desc,"Theora codec initialisation failed", 1024); break;
  case ERR_VORBIS:
    g_strlcpy(event->desc,"Vorbis codec initialisation failed", 1024); break;
  case ERR_MUNMAP:
    g_strlcpy(event->desc,"Problem to unmap buffer", 1024); break;
  case ERR_CLOSE:
    g_strlcpy(event->desc,"Problem to close file", 1024); break;    
  case ERR_BUFFERS_QUERY:
    g_strlcpy(event->desc,"Query buffer error", 1024); break;    
  case ERR_QBUF:
    g_strlcpy(event->desc,"Queue buffer error", 1024); break;    
  case ERR_DQBUF:
    g_strlcpy(event->desc,"Dequeue buffer error", 1024); break;    
  case ERR_STREAMOFF:
    g_strlcpy(event->desc,"Device deny \"stream off\" command", 1024); break;
  case ERR_NO_DEVICE:
    g_strlcpy(event->desc,"You don't have video device", 1024); break;
  case ERR_NO_DATA:
    g_strlcpy(event->desc,"No data to process", 1024); break;
  case ERR_CONFIG:
    g_strlcpy(event->desc,"Config file have strange format", 1024); break;
  case ERR_REGCOMP:
    g_strlcpy(event->desc,"Can't compile regular extension", 1024); break;
  case ERR_GUI:
    g_strlcpy(event->desc,"Graphical user intreface error", 1024); break;
  case ERR_AUDIO:
    g_strlcpy(event->desc,"Problem with audio device", 1024); break;
  default:
  case ERR_UNDEFINED:
    g_strlcpy(event->desc,"Undefined error", 1024); break;
  }
#ifdef VERBOSE
  g_printf("ERROR: %s  (%s:%d)\n",event->desc, event->file, event->line);
#endif
  return code;
}

int debug_error2(int code, const char *param, int line, const char *file) {
  event_t *event;

  if (code >= 0) 
    return code;

  event = new_event();
  event->type = TYPE_ERROR;
  event->code = code;
  event->file = file;
  event->line = line;
  switch(code) {
  case ERR_OPEN: 
    g_sprintf(event->desc,"Can't open %s",param); break;
  case ERR_NO_V4L2:
    g_sprintf(event->desc,"%s problably not an v4l2 device", param); break;
  case ERR_NO_CAPTURE:
    g_sprintf(event->desc,"%s can't capture", param); break;
  case ERR_FORMAT:
    g_strlcpy(event->desc,"%s don't want accept proposed pixel format", 1024); break;
  default:
  case ERR_UNDEFINED:
    g_strlcpy(event->desc,"Undefined error", 1024); break;
  }
#ifdef VERBOSE
  g_printf("ERROR: %s  (%s:%d)\n",event->desc, event->file, event->line);
#endif
  return code;
}

const char *debug_message() {
  time_t tm = time(NULL);
  int i;

  if (string == NULL) string = g_string_new("");
  else string = g_string_assign(string, "");

  g_string_append_printf(string, " Debug report generated: %s", ctime(&tm));
  g_string_append(string, "-------------------------------------------------------\n");
  for (i=0; i<debug.queue; i++) {
    if (debug.events[i].type == TYPE_FUNC_TRACE) {
      g_string_append_printf(string, " %s (%s:%d)\n", 
			     debug.events[i].desc,
			     debug.events[i].file, debug.events[i].line);
    } else if (debug.events[i].type == TYPE_ERROR) {
      g_string_append_printf(string, " \nError: %s (%d)\n at: %s:%d\n\n", 
			     debug.events[i].desc, debug.events[i].code * -1,
			     debug.events[i].file, debug.events[i].line);
    }
  }
  g_string_append(string, "-------------------------------------------------------\n");
  g_string_append_printf(string, " %s %s, bug reports: %s\n", 
			 PACKAGE_NAME, PACKAGE_VERSION, PACKAGE_BUGREPORT);

  return string->str;
}

void debug_flush() {
  int i, flush=0;

  for (i=0; i<debug.queue; i++)
    if (debug.events[i].type == TYPE_ERROR)
      flush=1;

  if (flush)
    g_printf("Flush debug buffer\n\n%s\n",debug_message());

  if (string != NULL)
    g_string_free(string, TRUE);
}
